package com.arialyy.frame.http;

import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.text.TextUtils;

import com.arialyy.frame.cache.CacheUtil;
import com.arialyy.frame.http.inf.IResponse;
import com.arialyy.frame.util.show.L;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.Headers;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

/**
 * Created by lyy on 2015/11/5.
 * 网络连接工具
 */
public class HttpUtil {
    private static final    String   TAG      = "HttpUtil";
    private                 Context  mContext = null;
    private static volatile HttpUtil mUtil    = null;
    private static final    Object   LOCK     = new Object();
    private CacheUtil mCacheUtil;
    private Handler   mHandler;
    private static final int    TIME_OUT          = 5000;
    public static final  String CONTENT_TYPE_IMG  = "image/*";
    public static final  String CONTENT_TYPE_TEXT = "text/*";
    public static final  String CONTENT_TYPE_FILE = "application/octet-stream";

    private HttpUtil() {
    }

    private HttpUtil(Context context) {
        mContext = context;
        mCacheUtil = new CacheUtil(mContext, false);
        mHandler = new Handler(Looper.getMainLooper());
    }

    public static HttpUtil getInstance(Context context) {
        if (mUtil == null) {
            synchronized (LOCK) {
                if (mUtil == null) {
                    mUtil = new HttpUtil(context);
                }
            }
        }
        return mUtil;
    }

    public void get(final @NonNull String url, @NonNull final IResponse absResponse) {
        get(url, null, absResponse, false);
    }

    public void get(final @NonNull String url, @NonNull final IResponse absResponse, boolean useCache) {
        get(url, null, absResponse, useCache);
    }

    public void get(final @NonNull String url, final Map<String, String> params,
                    @NonNull final IResponse absResponse) {
        get(url, params, absResponse, false);
    }

    public void post(final @NonNull String url, @NonNull final IResponse absResponse) {
        post(url, null, null, absResponse, false);
    }

    public void post(final @NonNull String url, final Map<String, String> params,
                     @NonNull final IResponse absResponse) {
        post(url, params, null, absResponse, false);
    }

    public void post(final @NonNull String url, final Map<String, String> params,
                     @NonNull final IResponse absResponse, final boolean useCache) {
        post(url, params, null, absResponse, useCache);
    }

    public void post(final @NonNull String url, final Map<String, String> params,
                     final Map<String, String> header, @NonNull final IResponse absResponse) {
        post(url, params, header, absResponse, false);
    }

    /**
     * 上传文件
     *
     * @param key 上传文件键值
     */
    public void uploadFile(@NonNull final String url, @NonNull final String filePath, @NonNull final String key,
                           final String contentType, final Map<String, String> header, @NonNull final IResponse absResponse) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                File   file         = new File(filePath);
                String BOUNDARY     = UUID.randomUUID().toString(); // 边界标识 随机生成
                String PREFIX       = "--", LINE_END = "\r\n";
                String CONTENT_TYPE = "multipart/form-data"; // 内容类型
                try {
                    HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
                    conn.setReadTimeout(5000);
                    conn.setConnectTimeout(5000);
                    conn.setDoInput(true);
                    conn.setDoOutput(true);
                    conn.setUseCaches(false);
                    conn.setRequestMethod("POST");
                    conn.setRequestProperty("Charset", "utf-8"); // 设置编码
                    conn.setRequestProperty("connection", "keep-alive");
                    conn.setRequestProperty("Content-Type", CONTENT_TYPE + ";boundary=" + BOUNDARY);

                    if (header != null && header.size() > 0) {
                        Set set = header.entrySet();
                        for (Object aSet : set) {
                            Map.Entry entry = (Map.Entry) aSet;
                            conn.setRequestProperty(entry.getKey() + "", entry.getValue() + "");
                        }
                    }
                    OutputStream     outputSteam = conn.getOutputStream();
                    DataOutputStream dos         = new DataOutputStream(outputSteam);
                    StringBuilder    sb          = new StringBuilder();
                    sb.append(PREFIX);
                    sb.append(BOUNDARY);
                    sb.append(LINE_END);
                    sb.append("Content-Disposition: form-data; name=\"").append(key).append("\"; filename=\"").append(file.getName()).append("\"").append(LINE_END);
                    sb.append("Content-Type:").append(contentType).append("; charset=utf-8").append(LINE_END);
                    sb.append(LINE_END);
                    dos.write(sb.toString().getBytes());
                    InputStream is    = new FileInputStream(file);
                    byte[]      bytes = new byte[1024];
                    int         len   = 0;
                    while ((len = is.read(bytes)) != -1) {
                        dos.write(bytes, 0, len);
                    }
                    is.close();
                    dos.write(LINE_END.getBytes());
                    byte[] end_data = (PREFIX + BOUNDARY + PREFIX + LINE_END).getBytes();
                    dos.write(end_data);
                    dos.flush();
                    int res = conn.getResponseCode();
                    if (res == 200) {
                        BufferedInputStream inputStream   = new BufferedInputStream(conn.getInputStream());
                        byte[]              buf           = new byte[1024];
                        StringBuilder       stringBuilder = new StringBuilder();
                        while (inputStream.read(buf) > 0) {
                            stringBuilder.append(new String(buf, 0, buf.length));
                        }
                        String data = stringBuilder.toString();
                        L.j(data);
                        absResponse.onResponse(data);
                    } else {
                        absResponse.onError("error");
                    }
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }


    /**
     * 基本get方法
     */
    public void get(final @NonNull String url, final Map<String, String> params,
                    @NonNull final IResponse absResponse, final boolean useCache) {
        L.v(TAG, "请求链接 >>>> " + url);
        String requestUrl = url;
        if (params != null && params.size() > 0) {
            Set set = params.entrySet();
            int i   = 0;
            requestUrl += "?";
            for (Object aSet : set) {
                i++;
                Map.Entry entry = (Map.Entry) aSet;
                requestUrl += entry.getKey() + "=" + entry.getValue() + (i < params.size() ? "&" : "");
            }
            L.v(TAG, "请求参数为 >>>> ");
            L.m(params);
        }

        OkHttpClient client = new OkHttpClient.Builder().connectTimeout(TIME_OUT, TimeUnit.MILLISECONDS)
                .writeTimeout(TIME_OUT, TimeUnit.MILLISECONDS).readTimeout(300000, TimeUnit.MILLISECONDS).build();
        final Request request = new Request.Builder().url(requestUrl).build();
        Call          call    = client.newCall(request);

        //请求加入调度
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                L.e(TAG, "请求链接【" + url + "】失败");
                String data = null;
                if (useCache) {
                    data = mCacheUtil.getStringCache(url + L.m2s(params));
                    L.d(TAG, "数据获取成功，获取到的数据为 >>>> ");
                    L.j(data);
                }
                if (TextUtils.isEmpty(data)) {
                    setOnError(request, absResponse);
                } else {
                    setOnResponse(data, absResponse);
                }
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String data = response.body().string();
                L.d(TAG, "数据获取成功，获取到的数据为 >>>> ");
                L.j(data);
                if (useCache) {
                    L.v(TAG, "缓存链接【" + url + "】的数据");
                    mCacheUtil.putStringCache(url + L.m2s(params), data);
                }
                setOnResponse(data, absResponse);
            }
        });
    }

    /**
     * 基本的Post方法
     */
    public void post(final @NonNull String url, final Map<String, String> params,
                     final Map<String, String> header, @NonNull final IResponse absResponse,
                     final boolean useCache) {
        L.v(TAG, "请求链接 >>>> " + url);
        OkHttpClient client = new OkHttpClient.Builder().connectTimeout(TIME_OUT, TimeUnit.MILLISECONDS)
                .writeTimeout(TIME_OUT, TimeUnit.MILLISECONDS).readTimeout(300000, TimeUnit.MILLISECONDS).build();
        FormBody.Builder formB = new FormBody.Builder();
        //头数据
        Headers.Builder hb = new Headers.Builder();
        if (header != null && header.size() > 0) {
            Set set = header.entrySet();
            for (Object aSet : set) {
                Map.Entry entry = (Map.Entry) aSet;
                hb.add(entry.getKey() + "", entry.getValue() + "");
            }
            L.v(TAG, "请求的头数据为 >>>> ");
            L.m(header);
        }
        //请求参数
        if (params != null && params.size() > 0) {
            Set set = params.entrySet();
            for (Object aSet : set) {
                Map.Entry entry = (Map.Entry) aSet;
                formB.add(entry.getKey() + "", entry.getValue() + "");
            }
            L.v(TAG, "请求参数为 >>>> ");
            L.m(params);
        } else {
            formB.add("null", "null");
        }

        Request request = new Request.Builder().url(url).post(formB.build()).headers(hb.build()).build();
        Call    call    = client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                L.e(TAG, "请求链接【" + url + "】失败");
                String data = null;
                if (useCache) {
                    data = mCacheUtil.getStringCache(url + L.m2s(params));
                    L.d(TAG, "从缓存读取的数据为 >>>> ");
                    L.j(data);
                }
                if (TextUtils.isEmpty(data)) {
                    setOnError(call, absResponse);
                } else {
                    setOnResponse(data, absResponse);
                }
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String data = response.body().string();
                L.d(TAG, "数据获取成功，获取到的数据为 >>>>");
                L.j(data);
                if (useCache) {
                    L.v(TAG, "缓存链接【" + url + "】的数据");
                    mCacheUtil.putStringCache(url + L.m2s(params), data);
                }
                setOnResponse(data, absResponse);
            }

        });
    }

    private void setOnError(final Object error, final IResponse response) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                response.onError(error);
            }
        });
    }

    private void setOnResponse(final String data, final IResponse response) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                response.onResponse(data);
            }
        });
    }

    /**
     * 返回String类型的响应
     */
    public static class AbsResponse implements IResponse {

        @Override
        public void onResponse(String data) {

        }

        @Override
        public void onError(Object error) {

        }
    }

}
